import * as jayson from 'jayson'
import createServer from 'connect'

const jsonParser = require('body-parser').json
const middleware = require('jayson/lib/server/middleware')

import { logger } from '@pkg/logger'
import { Wallet } from '@app/wallet'
import { BalanceManager } from './balances'
import * as config from '@config/server.json'

import { getBalance } from '@app/methods/get_balance'
import { newAccount } from '@app/methods/new_account'
import { getAccounts } from '@app/methods/get_accounts'
import { getTransaction } from '@app/methods/get_transaction'
import { transfer } from '@app/methods/transfer'
import { transferFrom } from '@app/methods/transfer_from'
import { transferToken } from '@app/methods/transfer_token'
import { transferTokenFrom } from '@app/methods/transfer_token_from'
import { sendFee } from '@app/methods/send_fee'
import { collection } from '@app/methods/collection'
import { getTaskStatus } from '@app/methods/get_task_status'
import { getWalletBalance } from '@app/methods/get_wallet_balance'

export class RpcServer {
    private wallet: Wallet
    private balances: BalanceManager

    constructor(wallet: Wallet, balances: BalanceManager) {
        this.wallet = wallet
        this.balances = balances
    }

    /**
     * 运行RPC服务
     * @param host - 主机地址
     * @param port - 端口号
     */
    async run(host: string, port: number) {
        const self = this
        const app = createServer()
        const router = this.router()
        const server = new jayson.Server(router)

        app.use(jsonParser())
        app.use(function(req: any, res: any, next: any) {
            if (!self.auth(req.headers)) {
                res.writeHead(401)
                res.end()
            } else {
                middleware(server)(req, res, next)
            }
        })
        logger.info('JSON-RPC2 server listening on %s:%s', host, port)
        app.listen(port, host)
    }

    /**
     * 校验权限(Basic Auth)
     * @param headers - HTTP头
     */
    private auth(headers: any) {
        const username = config.login.username
        const password = config.login.password
        if (username.length == 0) {
            return true
        }
        if (password.length == 0) {
            return true
        }
        if (!headers || !headers.authorization) {
            return false
        }
        const authorization = String(headers.authorization)
        const slice = authorization.split(' ')
        if (slice.length != 2 || slice[0] != 'Basic') {
            return false
        }

        const buffer = Buffer.from(slice[1], 'base64')
        const pair = buffer.toString().split(':')
        if (pair.length != 2) {
            return false
        }
        return pair[0] == username && pair[1] == password
    }

    /**
     * JSON RPC 接口路由处理
     */
    private router(): {[methodName: string]: jayson.MethodLike} {
        return {
            // 获取代币余额
            'getBalance': (params: any, callback: any) => {
                getBalance(this.wallet, params, callback)
            },

            // 创建新地址
            'newAccount': (params: any, callback: any) => {
                newAccount(this.wallet, params, callback)
            },

            // 获取地址列表
            'getAccounts': (params: any, callback: any) => {
                getAccounts(this.wallet, params, callback)
            },

            // 转移TRX代币
            'transfer': (params: any, callback: any) => {
                transfer(this.wallet, params, callback)
            },

            // 从指定地址TRX代币
            'transferFrom': (params: any, callback: any) => {
                transferFrom(this.wallet, params, callback)
            },

            // 转移TRC20代币
            'transferToken': (params: any, callback: any) => {
                transferToken(this.wallet, params, callback)
            },

            // 从指定地址转移TRC20代币
            'transferTokenFrom': (params: any, callback: any) => {
                transferTokenFrom(this.wallet, params, callback)
            },

            // 获取交易信息
            'getTransaction': (params: any, callback: any) => {
                getTransaction(this.wallet, params, callback)
            },

            // 发送手续费
            'sendFee': (params: any, callback: any) => {
                sendFee(this.wallet, params, callback)
            },

            // 资金归集
            'collection': (params: any, callback: any) => {
                collection(this.wallet, params, callback)
            },

            // 获取任务状态
            'getTaskStatus': (params: any, callback: any) => {
                getTaskStatus(this.wallet, params, callback)
            },

            // 获取钱包余额
            'getWalletBalance': (params: any, callback: any) => {
                getWalletBalance(this.balances, params, callback)
            }
        }
    }
}
